/*!
 * \file WtSimpDataMgr.cpp
 * \project WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief 简单数据管理器实现
 * 
 * \details 本文件实现了WonderTrader执行监控系统的简单数据管理器类WtSimpDataMgr，
 *          负责执行监控系统的数据存储、缓存和管理功能。
 *          
 *          主要实现功能：
 *          - 实时行情数据缓存和管理
 *          - K线数据的存储和查询
 *          - 数据读取器的集成和管理
 *          - 时间信息的维护和提供
 *          - 基础数据服务的代理
 *          - 行情数据推送处理
 *          
 *          该实现是执行监控系统中数据层的核心组件，为执行器提供必要的数据支持。
 */
#include "WtSimpDataMgr.h"
#include "WtExecRunner.h"
#include "../WtCore/WtHelper.h"

#include "../Share/StrUtil.hpp"
#include "../Includes/WTSDataDef.hpp"
#include "../Includes/WTSVariant.hpp"
#include "../Share/DLLHelper.hpp"
#include "../Includes/WTSSessionInfo.hpp"

#include "../WTSTools/WTSLogger.h"
#include "../WTSTools/WTSDataFactory.h"

USING_NS_WTP;

WTSDataFactory g_dataFact;		/*!< 全局数据工厂实例 */

/*!
 * \brief 构造函数
 * 
 * \details 初始化简单数据管理器，设置初始状态。
 *          所有指针成员初始化为NULL，缓存映射初始化为空。
 */
WtSimpDataMgr::WtSimpDataMgr()
	: _reader(NULL)
	, _runner(NULL)
	, _bars_cache(NULL)
	, _rt_tick_map(NULL)
{
}

/*!
 * \brief 析构函数
 * 
 * \details 释放分配的资源，包括实时tick数据缓存映射。
 *          确保系统退出时不会发生内存泄漏。
 */
WtSimpDataMgr::~WtSimpDataMgr()
{
	if (_rt_tick_map)
		_rt_tick_map->release();
}

/*!
 * \brief 初始化数据存储
 * 
 * \details 根据配置信息初始化数据读取器，建立与数据存储系统的连接。
 *          支持加载不同类型的数据读取器动态库，提供历史数据访问能力。
 * 
 * \param cfg 数据存储配置信息
 * \return 初始化是否成功
 * 
 * \note 数据读取器必须实现标准的IDataReader接口
 */
bool WtSimpDataMgr::initStore(WTSVariant* cfg)
{
	if (cfg == NULL)
		return false;

	std::string module = cfg->getCString("module");
	if (module.empty())
		module = WtHelper::getInstDir() + DLLHelper::wrap_module("WtDataStorage");
	else
		module = WtHelper::getInstDir() + DLLHelper::wrap_module(module.c_str());

	DllHandle hInst = DLLHelper::load_library(module.c_str());
	if (hInst == NULL)
	{
		WTSLogger::error("Data reader %s loading failed", module.c_str());
		return false;
	}

	FuncCreateDataReader funcCreator = (FuncCreateDataReader)DLLHelper::get_symbol(hInst, "createDataReader");
	if (funcCreator == NULL)
	{
		WTSLogger::error("Data reader %s loading failed: entrance function createDataReader not found", module.c_str());
		DLLHelper::free_library(hInst);
		return false;
	}

	_reader = funcCreator();
	if (_reader == NULL)
	{
		WTSLogger::error("Data reader %s creating api failed", module.c_str());
		DLLHelper::free_library(hInst);
		return false;
	}

	_reader->init(cfg, this);

	_s_info = _runner->get_session_info(cfg->getCString("session"), false);

	return true;
}

/*!
 * \brief 初始化数据管理器
 * 
 * \details 初始化简单数据管理器，设置执行运行器引用和数据存储配置。
 *          该函数是数据管理器的主要初始化入口。
 * 
 * \param cfg 配置信息，包含数据存储相关配置
 * \param runner 执行运行器指针，用于获取基础数据服务
 * \return 初始化是否成功
 */
bool WtSimpDataMgr::init(WTSVariant* cfg, WtExecRunner* runner)
{
	_runner = runner;
	return initStore(cfg->get("store"));
}

/*!
 * \brief 所有K线数据更新完成回调
 * 
 * \details 当数据读取器完成一轮K线数据更新时的回调函数。
 *          在简单数据管理器中，该函数为空实现，不需要特殊处理。
 * 
 * \param updateTime 更新时间
 */
void WtSimpDataMgr::on_all_bar_updated(uint32_t updateTime)
{

}

/*!
 * \brief 获取基础数据管理器
 * 
 * \details 获取基础数据管理器的指针，代理执行运行器的基础数据服务。
 *          基础数据管理器提供品种、合约、交易时段等基础信息。
 * 
 * \return 基础数据管理器指针
 */
IBaseDataMgr* WtSimpDataMgr::get_basedata_mgr()
{
	return _runner->get_bd_mgr();
}

/*!
 * \brief 获取热点管理器
 * 
 * \details 获取热点管理器的指针，代理执行运行器的热点合约服务。
 *          热点管理器提供主力合约、次主力合约等热点信息。
 * 
 * \return 热点管理器指针
 */
IHotMgr* WtSimpDataMgr::get_hot_mgr()
{
	return _runner->get_hot_mgr();
}

/*!
 * \brief 获取当前日期
 * 
 * \details 获取当前的日期信息，用于时间相关的计算和判断。
 * 
 * \return 当前日期（格式：yyyyMMdd）
 */
uint32_t WtSimpDataMgr::get_date()
{
	return _cur_date;
}

/*!
 * \brief 获取当前分钟时间
 * 
 * \details 获取当前的分钟时间信息，用于分钟级别的时间计算。
 * 
 * \return 当前分钟时间（格式：hhmm）
 */
uint32_t WtSimpDataMgr::get_min_time()
{
	return _cur_min_time;
}

/*!
 * \brief 获取当前秒数
 * 
 * \details 获取当前的秒数信息，包含秒和毫秒部分。
 * 
 * \return 当前秒数（格式：ssmmm，秒+毫秒）
 */
uint32_t WtSimpDataMgr::get_secs()
{
	return _cur_secs;
}

/*!
 * \brief 数据读取器日志回调
 * 
 * \details 数据读取器的日志回调函数，将日志消息转发给系统日志。
 *          确保数据读取器的日志能够统一管理。
 * 
 * \param ll 日志级别
 * \param message 日志消息
 */
void WtSimpDataMgr::reader_log(WTSLogLevel ll, const char* message)
{
	WTSLogger::log_raw(ll, message);
}

/*!
 * \brief K线数据更新回调
 * 
 * \details 当数据读取器有新的K线数据时的回调函数。
 *          在简单数据管理器中，该函数为空实现，不需要特殊处理。
 * 
 * \param code 合约代码
 * \param period K线周期
 * \param newBar 新的K线数据
 */
void WtSimpDataMgr::on_bar(const char* code, WTSKlinePeriod period, WTSBarStruct* newBar)
{

}

/*!
 * \brief 处理行情数据推送
 * 
 * \details 处理实时行情数据推送，更新tick数据缓存，
 *          维护当前时间信息（日期、时间、交易日等）。
 *          该函数确保时间信息的一致性和准确性。
 * 
 * \param stdCode 标准合约代码
 * \param curTick 新的tick数据指针
 * 
 * \note 该函数会自动维护时间信息的一致性，防止时间倒退
 */
void WtSimpDataMgr::handle_push_quote(const char* stdCode, WTSTickData* curTick)
{
	if (curTick == NULL)
		return;

	if (_rt_tick_map == NULL)
		_rt_tick_map = DataCacheMap::create();

	_rt_tick_map->add(stdCode, curTick, true);

	uint32_t uDate = curTick->actiondate();
	uint32_t uTime = curTick->actiontime();

	if (_cur_date != 0 && (uDate < _cur_date || (uDate == _cur_date && uTime < _cur_act_time)))
	{
		return;
	}

	_cur_date = uDate;
	_cur_act_time = uTime;

	uint32_t _cur_raw_time = _cur_act_time / 100000;
	uint32_t _cur_secs = _cur_act_time % 100000;
	uint32_t minutes = _s_info->timeToMinutes(_cur_raw_time);
	bool isSecEnd = _s_info->isLastOfSection(_cur_raw_time);
	if (isSecEnd)
	{
		minutes--;
	}
	minutes++;
	_cur_min_time = _s_info->minuteToTime(minutes);
	_cur_tdate = curTick->tradingdate();
}

/*!
 * \brief 获取最新tick数据
 * 
 * \details 获取指定合约的最新tick数据，从实时数据缓存中获取。
 *          返回的数据已经增加引用计数，调用者需要负责释放。
 * 
 * \param code 合约代码
 * \return 最新tick数据指针，未找到时返回NULL
 * 
 * \note 返回的数据已经增加引用计数，调用者需要负责释放
 */
WTSTickData* WtSimpDataMgr::grab_last_tick(const char* code)
{
	if (_rt_tick_map == NULL)
		return NULL;

	WTSTickData* curTick = (WTSTickData*)_rt_tick_map->get(code);
	if (curTick == NULL)
		return NULL;

	curTick->retain();
	return curTick;
}

/*!
 * \brief 获取tick数据切片
 * 
 * \details 获取指定合约的历史tick数据切片，用于技术分析和策略计算。
 *          数据来源于数据读取器，支持指定数量和结束时间。
 * 
 * \param code 合约代码
 * \param count 数据条数
 * \param etime 结束时间，0表示最新时间
 * \return tick数据切片指针，失败时返回NULL
 * 
 * \note 返回的数据需要调用者负责释放
 */
WTSTickSlice* WtSimpDataMgr::get_tick_slice(const char* code, uint32_t count, uint64_t etime /*= 0*/)
{
	if (_reader == NULL)
		return NULL;

	return _reader->readTickSlice(code, count, etime);
}

/*!
 * \brief 获取K线数据切片
 * 
 * \details 获取指定合约和周期的K线数据切片，支持多种K线周期和倍数。
 *          对于非基础周期的K线，会进行实时合成处理。
 * 
 * \param stdCode 合约代码
 * \param period K线周期（分钟、小时、日线等）
 * \param times 周期倍数（如5分钟线的times为5）
 * \param count 数据条数
 * \param etime 结束时间，0表示最新时间
 * \return K线数据切片指针，失败时返回NULL
 * 
 * \note 返回的数据需要调用者负责释放
 */
WTSKlineSlice* WtSimpDataMgr::get_kline_slice(const char* stdCode, WTSKlinePeriod period, uint32_t times, uint32_t count, uint64_t etime /*= 0*/)
{
	if (_reader == NULL)
		return NULL;

	std::string key = StrUtil::printf("%s-%u", stdCode, period);

	if (times == 1)
	{
		return _reader->readKlineSlice(stdCode, period, count, etime);
	}

	//只有非基础周期的K线数据才需要处理
	WTSSessionInfo* sInfo = _runner->get_session_info(stdCode, true);

	if (_bars_cache == NULL)
		_bars_cache = DataCacheMap::create();

	key = StrUtil::printf("%s-%u-%u", stdCode, period, times);

	WTSKlineData* kData = (WTSKlineData*)_bars_cache->get(key);
	//只有当K线数据不存在或数据条数不足时，才需要从数据读取器中读取
	if (kData == NULL || kData->size() < count)
	{
		uint32_t realCount = count * times + times;
		WTSKlineSlice* rawData = _reader->readKlineSlice(stdCode, period, realCount, etime);
		if (rawData != NULL)
		{
			kData = g_dataFact.extractKlineData(rawData, period, times, sInfo, true);
			rawData->release();
		}
		else
		{
			return NULL;
		}

		if (kData)
			_bars_cache->add(key, kData, false);
	}

	int32_t sIdx = 0;
	uint32_t rtCnt = min(kData->size(), count);
	sIdx = kData->size() - rtCnt;
	WTSBarStruct* rtHead = kData->at(sIdx);
	WTSKlineSlice* slice = WTSKlineSlice::create(stdCode, period, times, rtHead, rtCnt);
	return slice;
}
